package com.finesys.backend.user.service.user;

import com.alibaba.druid.util.StringUtils;
import com.finesys.backend.common.constant.BusinessCode;
import com.finesys.backend.common.constant.CacheKeyDefine;
import com.finesys.backend.common.model.base.BusinessResult;
import com.finesys.backend.common.model.base.PageRequest;
import com.finesys.backend.common.model.base.PageResult;
import com.finesys.backend.common.model.user.UserModel;
import com.finesys.backend.common.utils.*;
import com.finesys.backend.service.user.UserService;
import com.finesys.backend.user.mapper.UserMapper;
import com.finesys.backend.user.service.redis.RedisService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * <p>Title: 用户service</p>
 * <p>Description: </p>
 * <p>Copyright: CopyRight (c) 2020-2035</p>
 * <p>Company: finesys Co. LTD.</p>
 * <p>Author: lehoon</p>
 * <p>Date: 2020.10.18</p>
 */
@Slf4j
@DubboService(version = "1.0.0", interfaceName = "com.finesys.backend.service.user.UserService", timeout = 600000, retries = 0)
public class UserServiceImpl implements UserService {
	@Resource
	private UserMapper userMapper;
	@Resource
	private RedisService redisService;

	@Override
	public BusinessResult<PageResult> findPage(PageRequest request) {
		PageHelper.startPage(request.getPage(), request.getLimit(), " createtime desc ");
		List<UserModel> userModelList = userMapper.findList();
		BusinessResult<PageResult> result = new BusinessResult<PageResult>();
		PageInfo<UserModel> userPageInfo = new PageInfo<UserModel>(userModelList);
		PageResult pageResult = new PageResult(userPageInfo.getPageNum(),
				userPageInfo.getPageSize(),
				userPageInfo.getPages(),
				userPageInfo.getTotal(),
				userPageInfo.getList());

		result.success(pageResult);
		return result;
	}

	@Override
	public List<UserModel> findList() {
		return userMapper.findList();
	}

	@Override
	public BusinessResult<String> login(String username, String password, String remoteIp) {
		BusinessResult<String> result = new BusinessResult<String>();
		try {
			UserModel userModel = userMapper.findUserByUserName(username);
			if(userModel.getPassword().equalsIgnoreCase(MD5.md5(password))) {
				result.setCode(BusinessCode.SUCCESS.getCode());
				result.setMessage("登陆成功");
				userModel.setRemoteAddress(remoteIp);
				result.setData(this.createMemberTokenForWeb(userModel));
				return result;
			}

			result.setCode(101);
			result.setMessage("密码错误");
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e.getMessage());
			result.setCode(102);
			result.setMessage("系统发生错误,登陆失败");
			return result;
		}
	}
	
	/**
	 * 为web端登录用户创建token
	 * @param userModel
	 * @return
	 */
	public String createMemberTokenForWeb(UserModel userModel) {
		userModel.setPassword("");
		String token = getToken(userModel.getId(), userModel.getRemoteAddress());
		redisService.setUserForWeb(String.format("%s%s", CacheKeyDefine.USER_TOKEN_CACHE_PREFIX, token), userModel);
		return token;
	}
	
	/**
	 * 重新刷新token有效期（web）
	 * @param token
	 * @param userModel
	 */
	public void refreshMemberForWeb(String token, UserModel userModel) {
		redisService.setUserForWeb(token, userModel);
	}
	
	private String getToken(String id, String ip) {
        // 随机生成一个字符串
        String content = MD5Tools.encode(UUID.randomUUID().toString() + id);
        String sign = "";
        // 加签名
        try {
        	String newKey = String.format("%s-%s", Const.ACCESS_TOKEN_DEVOPS_SIGN_KEY, ip);
            sign = HmacsHa1.getSignature(content, newKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return content + sign;
    }

    @Override
    public boolean checkTokenSign(String token, String ip) {
		//0 - 32
        String content = token.substring(0, 32);
        //sign 32 - end
        String sign = token.substring(32);
        try {
        	//这里用的druid的string工具类，为防有坑，做个标记
			String newKey = String.format("%s-%s", Const.ACCESS_TOKEN_DEVOPS_SIGN_KEY, ip);
            if (StringUtils.equals(sign, HmacsHa1.getSignature(content, newKey))) {
                return true;
            } else {
                return false;
            }
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return false;
    }

	@Override
	public BusinessResult<UserModel> validateToken(String token) {
		String redisToken = String.format("%s%s", CacheKeyDefine.USER_TOKEN_CACHE_PREFIX, token);
		UserModel userModel = redisService.getUserByToken(redisToken);
		if(userModel == null){
			String refreshToken = String.format("%s%s", CacheKeyDefine.USER_REFRESHTOKEN_CACHE_PREFIX, token);
			String userId = redisService.getUserIdByToken(refreshToken);
			if(userId != null){
				userModel = userMapper.getUserById(userId);
				if(userModel != null){
					refreshMemberForWeb(redisToken, userModel);
					redisService.setUserIdForWeb(refreshToken, userId);
				}
			}
		}
		BusinessResult<UserModel> result = new BusinessResult<UserModel>();
		result.success(userModel);
		return result;
	}

	@Override
	public BusinessResult<UserModel> logout(String token) {
		UserModel userModel = redisService.getUserByToken(String.format("%s%s", CacheKeyDefine.USER_TOKEN_CACHE_PREFIX, token));
		if (userModel != null) {
			redisService.deleteUserToken(String.format("%s%s", CacheKeyDefine.USER_TOKEN_CACHE_PREFIX, token));
		}

		BusinessResult<UserModel> result = new BusinessResult<UserModel>();
		result.success(userModel);
		return result;
	}

	public void destroyToken(String token) {
    	this.redisService.evictRedis(String.format("%s%s", CacheKeyDefine.USER_TOKEN_CACHE_PREFIX, token));
    }

	@Override
	@Transactional(rollbackFor = Exception.class)
	public BusinessResult<UserModel> save(UserModel userModel) {
		UserModel oldUserModel = userMapper.findUserByUserName(userModel.getUsername());
		if(oldUserModel != null){
			return new BusinessResult<UserModel>(102, "创建失败，用户名已存在", userModel);
		}
		try {
			userModel.setStatus("1");
			userModel.setId(UuidUtil.get32UUID());
			userModel.setPassword(MD5.md5(userModel.getPassword()));
			userMapper.save(userModel);
			return new BusinessResult<UserModel>(200, "创建用户成功", userModel);
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e.getMessage());
			return new BusinessResult<UserModel>(102, "系统错误, 创建用户失败", userModel);
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public BusinessResult<String> update(UserModel userModel) {
		if(!StringUtils.isEmpty(userModel.getUsername())){
			UserModel oldUserModel = userMapper.findUserByUserName(userModel.getUsername());
			if(oldUserModel != null && !oldUserModel.getId().equals(userModel.getId())){
				return new BusinessResult<String>(102, "修改失败，用户名已存在");
			}
		}
		try {
			if(!StringUtils.isEmpty(userModel.getPassword())){
				userModel.setPassword(MD5.md5(userModel.getPassword()));
			}

			userMapper.update(userModel);
			return new BusinessResult<String>(200, "修改成功");
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e.getMessage());
			return new BusinessResult<String>(102, "系统错误, 修改失败");
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public BusinessResult<String> delete(String id) {
		try {
			userMapper.delete(id);
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e.getMessage());
			return new BusinessResult<String>(102, "系统发生异常,删除用户信息失败");
		}
		return new BusinessResult<String>(200, "删除用户信息成功");
	}

	@Override
	public BusinessResult<Long> queryUserCount() {
		long count = userMapper.queryUserCount();
		return new BusinessResult<Long>().success(count);
	}
}
